package com.zxp.common.core.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zxp.common.core.security.authentication.handler.MyAuthenticationFailHandler;
import com.zxp.common.core.security.authentication.handler.MyAuthenticationSuccessHandler;
import com.zxp.common.core.security.authorize.MyAuthorizationConfigurerService;
import com.zxp.common.core.security.authorize.ZxpAuthorizationConfigurerManager;
import com.zxp.common.core.security.authorize.impl.MyAuthorizationConfigurerServiceImpl;
import com.zxp.common.core.security.authorize.impl.ZxpAuthorizationConfigurerManagerImpl;
import com.zxp.common.core.security.properties.SecurityProperties;
import com.zxp.common.core.validatecode.impl.ImageValidateCodeService;
import com.zxp.common.core.validatecode.impl.SmsValidateCodeService;
import com.zxp.common.core.validatecode.sms.AliyunSmsSender;
import com.zxp.common.core.validatecode.sms.SmsSenderApi;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * @author shollin
 * @desc
 * @date 2021/7/7/007 1:27
 */
@Configuration
@EnableConfigurationProperties(SecurityProperties.class)
@RequiredArgsConstructor
@ConditionalOnBean(value = {RedisTemplate.class})
public class ZxpSecurityConfig {

    private final SecurityProperties securityProperties;
    private final RedisTemplate<String,Object> redisTemplate;
    private final ObjectMapper objectMapper;
    private final DataSource dataSource;
    private final RedisConnectionFactory redisConnectionFactory;

    /**
     *
     *  配置密码编码器，Spring Security 5.X必须配置，否则登录时报空指针异常
     *  NoOpPasswordEncoder.getInstance() : 明文密码
     *  new BCryptPasswordEncoder();  BCrypt加盐密码
     *  PasswordEncoderFactories.createDelegatingPasswordEncoder();
     * @return
     */
    @Bean
    @ConditionalOnMissingBean(PasswordEncoder.class)
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    @Bean
    //@ConditionalOnMissingBean(AuthenticationFailureHandler.class)
    public MyAuthenticationFailHandler authenticationFailureHandler(){
        return new MyAuthenticationFailHandler(objectMapper,securityProperties);
    }


    /**
     * 配置TokenRepository
     * @return
     */
    @Bean
    @ConditionalOnMissingBean(PersistentTokenRepository.class)
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        // 配置数据源
        jdbcTokenRepository.setDataSource(dataSource);
        // 第一次启动的时候自动建表（可以不用这句话，自己手动建表，源码中有语句的）
        // jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }

    /**
     * 手机短信验证码发送器
     * @return
     */
    @Bean
    @ConditionalOnMissingBean(SmsSenderApi.class)
    public SmsSenderApi smsSender() {
        return new AliyunSmsSender();
    }

    // 图片验证码服务
    @Bean
    @ConditionalOnMissingBean(ImageValidateCodeService.class)
    public ImageValidateCodeService imageValidateCodeService(){
        return new ImageValidateCodeService(securityProperties,redisTemplate);
    }

    // 短信验证码服务
    @Bean
    @ConditionalOnMissingBean(SmsValidateCodeService.class)
    public SmsValidateCodeService smsValidateCodeService(){
        return new SmsValidateCodeService(securityProperties,redisTemplate,smsSender());
    }

    // 哪些url放过授权
    @Bean
    public MyAuthorizationConfigurerService authorizationConfigurerService(){
        return new MyAuthorizationConfigurerServiceImpl(securityProperties);
    }


}
